import json
import datetime
from django.shortcuts import render
from web.forms.issues import IssuesModelForm
from web import models
from utils.pagination import Pagination
from django.http import JsonResponse
from web.forms.issues import IssuesReplayModelForm, ProjectInviteModelForm
from django.views.decorators.csrf import csrf_exempt
from django.utils.safestring import mark_safe
from utils.md5 import str_add_uid
from django.urls import reverse


# select筛选
class SelectFilter():
    def __init__(self, data_list, request, name):
        self.data_list = data_list
        self.request = request
        self.name = name

    def __iter__(self):
        yield mark_safe("<select class='select2' multiple='multiple' style='width:100%;' >")
        for item in self.data_list:
            key = str(item[0])
            text = item[1]
            selected = ""
            value_list = self.request.GET.getlist(self.name)  # 获取浏览器地址栏传入的参数的id列表 assign=1&assign=2
            if key in value_list:
                selected = "selected"
                value_list.remove(key)
            else:
                value_list.append(key)
            query_dict = self.request.GET.copy()
            query_dict._mutable = True
            query_dict.setlist(self.name, value_list)
            if 'page' in query_dict:
                query_dict.pop('page')

            param_url = query_dict.urlencode()  # 解码获取参数
            if param_url:
                url = "{}?{}".format(self.request.path_info, param_url)  # status=1&status=2&status=3&xx=1
            else:
                url = self.request.path_info

            html = "<option value='{url}' {selected} >{text}</option>".format(url=url, selected=selected, text=text)
            yield mark_safe(html)
        yield mark_safe("</select>")


# checkbox筛选条件生成器,用于在页面展示 选择框，并且选中之后浏览器地址栏会有对应的参数
class CheckFilter():
    def __init__(self, data_list, request, name):
        """

        :param data_list: 数据库中含有筛选对象的数据列表
        :param request:
        :param name: 允许的筛选关键词
        """
        self.data_list = data_list
        self.request = request
        self.name = name

    def __iter__(self):
        for item in self.data_list:
            key = str(item[0])
            text = item[1]
            ck = ''  # 选中状态的标记
            # 当前url的get值 和当前循环的key值相等 则表示选中状态
            value_list = self.request.GET.getlist(self.name)  # [1,2,3,danger]
            if key in value_list:  # 1
                ck = 'checked'
                value_list.remove(key)  # [2,3,danger]
            else:
                value_list.append(key)
            # 为自己生成url ，保留原来的筛选条件，依次增加
            query_dict = self.request.GET.copy()
            query_dict._mutable = True  # 为拷贝的get 设置可修改
            query_dict.setlist(self.name, value_list)  # status=2&status=3&priority=danger
            if 'page' in query_dict:
                query_dict.pop('page')

            param_url = query_dict.urlencode()

            if param_url:
                url = "{}?{}".format(self.request.path_info, param_url)  # status=1&status=2&status=3&xx=1
            else:
                url = self.request.path_info
            html = '<a href=%s><input type="checkbox" %s /><label>%s</label></a>' % (url, ck, text)
            yield mark_safe(html)


def issues(request, project_id):
    form = IssuesModelForm(request)
    invite_form = ProjectInviteModelForm()
    # 根据条件筛选
    # ?status=1&priority=danger
    allow_filter_name = ['status', 'priority', 'issues_type', 'assign', 'attention']  # 定义筛选的关键词列表
    condition = {}  # 初始化筛选条件字典
    for name in allow_filter_name:
        value_list = request.GET.getlist(name)  # 获取搜索条件的列表
        if not value_list:
            continue
        condition['%s__in' % name] = value_list  # {'status__in':[1,2]}

    # 分页获取当前项目下的问题列表
    queryset = models.Issues.objects.filter(project_id=project_id).filter(**condition).all()
    # 调用自定义的分页类
    page_object = Pagination(
        current_page=request.GET.get('page'),
        all_count=queryset.count(),
        base_url=request.path_info,
        query_params=request.GET,
        per_page=5,  # 每页显示数据条数
    )
    issues_list = queryset[page_object.start:page_object.end]

    if request.method == 'POST':
        form = IssuesModelForm(request, data=request.POST)
        if form.is_valid():
            # 添加form以外字段的值
            form.instance.project = request.tracer.project
            form.instance.creator = request.tracer.user
            form.save()
            return JsonResponse({'status': True, })
        return JsonResponse({'status': False, 'error': form.errors})

    # 获取项目所有的问题类型
    project_issues_type_list = models.IssuesType.objects.filter(project_id=project_id).values_list('id', 'title')
    # 项目相关所有用户 （创建者、参与者）
    project_total_user = [(request.tracer.project.creator.id, request.tracer.project.creator.username)]
    # 项目参与者
    project_join_user = models.ProjectUser.objects.filter(project_id=project_id).values_list('user_id',
                                                                                             'user__username')
    project_total_user.extend(project_join_user)

    return render(request, 'issues/issues.html',
                  {'form': form,
                   'invite_form': invite_form,
                   'issues_list': issues_list,
                   'page_html': page_object.page_html(),
                   'filter_list': [
                       {'title': '问题类型', 'filter': CheckFilter(project_issues_type_list, request, 'issues_type'), },
                       {'title': '状态', 'filter': CheckFilter(models.Issues.status_choices, request, 'status')},
                       {'title': '优先级', 'filter': CheckFilter(models.Issues.priority_choices, request, 'priority')},
                       {'title': '指派者', 'filter': SelectFilter(project_total_user, request, 'assign')},
                       {'title': '关注者', 'filter': SelectFilter(project_total_user, request, 'attention')},
                   ],
                   })


# 问题详情页
def issues_detail(request, project_id, issues_id):
    issues_obj = models.Issues.objects.filter(id=issues_id).first()
    form = IssuesModelForm(request, instance=issues_obj)
    return render(request, 'issues/issues_detail.html', {'form': form, 'issues_obj': issues_obj})


# 问题操作记录（回复、修改记录）
@csrf_exempt
def issues_record(request, project_id, issues_id):
    # 获取该问题下 所有的回复记录和修改记录，
    replay_data_list = []
    queryset = models.IssueReplay.objects.filter(issues_id=issues_id, issues__project_id=project_id)
    for item in queryset:
        # 构建数据字典
        data = {
            'id': item.id,
            'replay_type_text': item.get_reply_type_display(),
            'content': item.content,
            'creator': item.creator.username,
            'datetime': item.create_datetime.strftime("%Y-%m-%d %H:%M"),
            'parent_id': item.reply_id
        }
        replay_data_list.append(data)

    # 回复评论

    if request.method == 'POST':
        form = IssuesReplayModelForm(data=request.POST)
        if form.is_valid():
            form.instance.creator = request.tracer.user
            form.instance.reply_type = 2
            form.instance.issues_id = issues_id
            instance = form.save()
            info = {
                'id': instance.id,
                'replay_type_text': instance.get_reply_type_display(),
                'content': instance.content,
                'creator': instance.creator.username,
                'datetime': instance.create_datetime.strftime("%Y-%m-%d %H:%M"),
                'parent_id': instance.reply_id
            }
            return JsonResponse({'status': True, 'data': info})
        return JsonResponse({'status': False, 'error': form.errors})
    return JsonResponse({'status': True, 'replay_data_list': replay_data_list})


# 变更问题详情的内容
@csrf_exempt
def issues_change(request, project_id, issues_id):
    # 接收前端发来的数据字典 {'name': 'issues_type', 'value': '7'}
    post_dict = json.loads(request.body.decode('utf-8'))
    issues_obj = models.Issues.objects.filter(project_id=project_id, id=issues_id).first()
    name = post_dict.get('name')
    value = post_dict.get('value')
    field_obj = models.Issues._meta.get_field(name)  # 获取ORM中的字段对象

    # 获取修改记录方法
    def create_change_record(content):
        issues_record_object = models.IssueReplay.objects.create(
            reply_type=1,
            issues=issues_obj,
            content=content,
            creator=request.tracer.user,
        )
        issues_record_dict = {
            'id': issues_record_object.id,
            'replay_type_text': issues_record_object.get_reply_type_display(),
            'content': issues_record_object.content,
            'creator': issues_record_object.creator.username,
            'datetime': issues_record_object.create_datetime.strftime("%Y-%m-%d %H:%M"),
            'parent_id': issues_record_object.reply_id
        }
        return issues_record_dict

    # 1  数据库字段更新
    # 1.1 文本字段
    # 判断是否是文本字段
    if name in ['subject', 'desc', 'start_date', 'end_date']:
        if not value:  # 前端传入为空
            if not field_obj.null:  # 数据库要求不能为空
                return JsonResponse({'status': False, 'error': '该字段不能为空'})
            setattr(issues_obj, name, None)
            issues_obj.save()
            # 生成操作记录
            chang_record = "%s设置为空" % field_obj.verbose_name
        else:
            setattr(issues_obj, name, value)
            issues_obj.save()
            # 生成操作记录
            chang_record = "[%s]设置为 %s" % (field_obj.verbose_name, value)
        return JsonResponse({'status': True, 'data': create_change_record(chang_record)})
    # 1.2 FK字段（指派的对象要判断是否是项目创建者或者参与者）
    if name in ['issues_type', 'module', 'assign', 'parent']:
        if not value:  # 前端传入为空
            if not field_obj.null:  # 数据库要求不能为空
                return JsonResponse({'status': False, 'error': '该字段不能为空'})
            # 数据库允许为空
            setattr(issues_obj, name, None)
            issues_obj.save()
            # 生成操作记录
            change_record = "%s设置为空" % field_obj.verbose_name
        else:
            if name == 'assign':  # 如果是指派
                # 是否是项目创建者
                if value == str(request.tracer.project.creator_id):
                    instance = request.tracer.project.creator
                # 项目参与者或其他
                else:
                    project_user_obj = models.ProjectUser.objects.filter(project_id=project_id, user_id=value).first()
                    if project_user_obj:
                        instance = project_user_obj.user
                    else:
                        instance = None
                if not instance:
                    return JsonResponse({'status': False, 'error': "您选择的值不存在"})
                setattr(issues_obj, name, instance)
                issues_obj.save()
                change_record = "%s更新为 【%s】" % (field_obj.verbose_name, str(instance))
            # 条件判断：用户输入的值，是自己的值。
            else:
                # 根据字段名关联表，生成关联表的对象
                instance = field_obj.rel.model.objects.filter(id=value, project_id=project_id).first()
                if not instance:
                    return JsonResponse({'status': False, 'error': "您选择的值不存在"})
                setattr(issues_obj, name, instance)
                issues_obj.save()
                change_record = "%s更新为 【%s】" % (field_obj.verbose_name, str(instance))
        return JsonResponse({'status': True, 'data': create_change_record(change_record)})

    # 1.3 choice字段
    if name in ['priority', 'status', 'mode']:
        select_text = None  # 初始化choice文本
        for key, text in field_obj.choices:  # 遍历choices字段的元组内容
            if str(key) == value:
                select_text = text
        if not select_text:
            return JsonResponse({'status': False, 'error': "您选择的值不存在"})
        setattr(issues_obj, name, value)
        issues_obj.save()
        change_record = "%s 更新为 【%s】" % (field_obj.verbose_name, select_text)
        return JsonResponse({'status': True, 'data': create_change_record(change_record)})
    # 1.4 M2M字段
    if name in ['attention', ]:
        # {'name':'attention',value:[1,2,3]}
        # 判断 value是不是列表
        if not isinstance(value, list):
            return JsonResponse({'status': False, 'error': '数据格式错误'})
        # 判断还是否为空
        if not value:
            issues_obj.attention.set([])
            issues_obj.save()
            change_record = "%s设置为空" % field_obj.verbose_name
        else:
            # 需要判断value 的id成员是否是该项目的创建者或者参与者
            # 先将创建者加入到 用户字典 { 1:user1,2:user2,...}
            user_dict = {str(request.tracer.project.creator_id): request.tracer.project.creator.username}
            project_user_obj = models.ProjectUser.objects.filter(project_id=project_id)  # 获取该项目的参与者
            # 再将 参与者 加入到用户字典
            for item in project_user_obj:
                user_dict[str(item.user_id)] = item.user.username
            username_list = []  # 定义一个用户名列表
            for user_id in value:
                username = user_dict.get(user_id)  # 根据传入的id 到是用户字典中获取用户名
                if not username:
                    return JsonResponse({'status': False, 'error': '数据不存在'})
                username_list.append(username)
            issues_obj.attention.set(value)
            issues_obj.save()
            change_record = "%s更新为【%s】" % (field_obj.verbose_name, ','.join(username_list))
        return JsonResponse({'status': True, 'data': create_change_record(change_record)})

    return JsonResponse({'status': False})


# 项目邀请成员，生成带邀请码的url
def invite_url(request, project_id):
    """
        1. 创建随机的邀请码
        2. 验证码保存到数据库
        3. 限制：只有创建者才能邀请
        """
    form = ProjectInviteModelForm(data=request.POST)
    if form.is_valid():
        # 如果不是项目创建者 则不能 生成邀请码
        if request.tracer.user != request.tracer.project.creator:
            form.add_error('period', '当前用户非项目创建者，无法邀请成员')
            return JsonResponse({'status': False, 'error': form.errors})
        # 根据当前用户手机号码生成随机邀请码
        code = str_add_uid(request.tracer.user.mobile_phone)
        # 保存到数据库
        form.instance.project = request.tracer.project
        form.instance.creator = request.tracer.user
        form.instance.code = code
        form.save()

        # 将验证码 和前面的地址拼接，生成新的验证码url 返回给前端展示

        url = "{scheme}://{host}{path}".format(
            scheme=request.scheme,  # 访问协议
            host=request.get_host(),  # 主机地址
            path=reverse('invite_join', kwargs={'code': code})
        )
        return JsonResponse({'status': True, 'data': url})
    return JsonResponse({'status': False, 'error': form.errors})


# 进去邀请链接，加入项目
def invite_join(request, code):
    invite_obj = models.ProjectInvite.objects.filter(code=code).first()
    if not invite_obj:
        return render(request, 'invite.html', {'error': '邀请码不存在'})
    # 如果当前用户为项目创建者，则无法加入此项目
    if invite_obj.project.creator == request.tracer.user:
        return render(request, 'invite.html', {'error': '创建者无需加入项目'})
    # 判断 该用户是否已经加入此项目
    join_user_obj = models.ProjectUser.objects.filter(user=request.tracer.user, project=invite_obj.project).first()
    if join_user_obj:
        return render(request, 'invite.html', {'error': '您已加入此项目，无需重复加入'})

    # 判断 项目成员 是否超出限制 (创建者+ 参与者)
    current_member_num = models.ProjectUser.objects.filter(project=invite_obj.project).count() + 1

    # 最大允许成员数
    # max_member_num = request.tracer.price_policy.project_member
    # ####### 问题1： 最多允许的成员(要进入的项目的创建者的限制）#######
    # max_member = request.tracer.price_policy.project_member # 当前登录用户他限制
    current_datetime = datetime.datetime.now()  # 当前时间
    # 是否已过期，如果已过期则使用免费额度
    max_transaction = models.Transaction.objects.filter(user=invite_obj.project.creator).order_by('-id').first()
    if max_transaction.price_policy.category == 1:
        max_member = max_transaction.price_policy.project_member
    else:
        if max_transaction.end_datetime < current_datetime:
            free_object = models.PricePolicy.objects.filter(category=1).first()
            max_member = free_object.per_project_member
        else:
            max_member = max_transaction.price_policy.per_project_member

    if current_member_num >= max_member:
        return render(request, 'invite.html', {'error': '项目成员超限，请升级套餐'})

    # 判断邀请码是否过期

    limit_datetime = invite_obj.datetime + datetime.timedelta(minutes=invite_obj.period)  # 过期时间
    if current_datetime > limit_datetime:
        return render(request, 'invite.html', {'error': '邀请码已过期'})

    # 数量限制
    if invite_obj.count:
        if invite_obj.use_count >= invite_obj.count:
            return render(request, 'invite.html', {'error': '邀请码数据已使用完'})
        invite_obj.use_count += 1
        invite_obj.save()
    # 创建 参与者和项目关联表数据

    models.ProjectUser.objects.create(user=request.tracer.user, project=invite_obj.project)
    # ####### 问题2： 更新项目参与成员 #######
    invite_obj.project.join_count += 1
    invite_obj.project.save()
    return render(request, 'invite.html', {'project': invite_obj.project})
